﻿using System;
using System.Threading;

namespace Utils
{
    public class Timer2 : IDisposable
    {
        #region Attributes

        private readonly Timer _timer;
    	private bool _autoReset;
    	private string _name;

        #endregion

        #region Properties

        public int Interval { get; set; }
        public bool Started { get; private set; }

    	public bool AutoReset
    	{
    		get
    		{
				return _autoReset;
    		}
			set
			{
				if (_autoReset != value)
				{
					if (this.Started)
					{
						throw new InvalidOperationException("The autoreset property cannot be changed with the Timer started");
					}
					else
					{
						_autoReset = value;
					}
				}
			}
    	}

        #endregion

        #region Events

        public event EventHandler<EventArgs> Elapsed;

        #endregion

        #region Public Methods

        public Timer2(int interval, string name)
        {
			_name = name;

            this.Interval = interval;
        	
        	_timer = new Timer(this.OnElapsed);
            _timer.Change(Timeout.Infinite, this.Interval);
        }

        public void Start()
        {
            if (this.Interval <= 0)
            {
                throw new InvalidOperationException("Invalid timer interval smaller than 0");
            }

            _timer.Change(this.Interval, this.AutoReset ? this.Interval : 0);

            this.Started = true;
        }

        public void Stop()
        {

            _timer.Change(Timeout.Infinite, this.Interval);
            this.Started = false;
        }

        protected virtual void OnElapsed(object o)
        {
            if (string.IsNullOrEmpty(Thread.CurrentThread.Name))
            {
                Thread.CurrentThread.Name = _name;
            }

            if (this.Elapsed != null)
            {
                this.Elapsed(this, EventArgs.Empty);
            }

			if (!this.AutoReset)
			{
				this.Started = false;
			}
        }

        #endregion

        #region IDisposable

        protected bool Disposed { get; private set; }

        private void Dispose(bool disposing)
        {
            if (!this.Disposed)
            {
                this.InternalDispose(disposing);
            }

            this.Disposed = true;
        }

        protected virtual void InternalDispose(bool disposing)
        {
            if (disposing)
            {
                _timer.Dispose();
            }

            // Dispose here only unmanaged objects 
            // Don’t use managed objects here because maybe 
            // they have been finalized already
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~Timer2()
        {
            this.Dispose(false);
        }

        #endregion
    }
}